#include "app_buffer.h"
#include <string.h>
#include "log.h"
#include <stdlib.h>



/**
 * @brief 创建缓冲区
 * 
 * @return app_buffer_t 
 * 步骤 ：
 * 1. 创建主缓冲区结构体
 * 2  创建子缓冲区结构体
 * 3  设定读写下标
 */
app_buffer_t *app_buffer_init()
{
   // 1. 创建主缓冲区结构体
    app_buffer_t *buffer = (app_buffer_t *)malloc(sizeof(app_buffer_t));
    //2  创建子缓冲区结构体
    for (int i = 0; i < 2; i++)
    {
        buffer->sub_buffer[i] = (sub_app_buffer_t *)malloc(sizeof(sub_app_buffer_t));
        buffer->sub_buffer[i]->data_ptr = (char *)malloc(APP_BUFFER_MAX_LEN);
        buffer->sub_buffer[i]->data_len = 0;
        buffer->sub_buffer[i]->total_len = APP_BUFFER_MAX_LEN;
    }
    // 3  设定读写下标
    buffer->read_index = 0;
    buffer->write_index = 1;

        // 4  初始化锁
    pthread_mutex_init(&buffer->read_lock, NULL);
    pthread_mutex_init(&buffer->swap_lock, NULL);

    return buffer;


}

/**
 * @brief 切换读写缓冲区
 */
void app_buffer_swap(app_buffer_t *buffer)
{
    pthread_mutex_lock(&buffer->swap_lock);
    buffer->write_index =  buffer->write_index == 0 ? 1 : 0;
    buffer->read_index =  buffer->read_index == 0 ? 1 : 0;
    pthread_mutex_unlock(&buffer->swap_lock);
}


/**
 * @brief 向缓冲区写入数据
 * @param app_buffer_t* 缓冲区指针
 * @return int 写入成功返回0，失败返回-1
 * 步骤：
 *  1 获取当前负责写的子缓冲区指针
 *  2 写入数据 （1 数据长度作为帧头， 2 数据内容作为帧体）
 *  3 增加缓冲区数据长度
 */
int app_buffer_write(app_buffer_t *buffer, char *write_data, int write_data_len)
{
    pthread_mutex_lock(&buffer->swap_lock);
//  *  1 获取当前负责写的子缓冲区指针
    sub_app_buffer_t *write_sub_buffer = buffer->sub_buffer[buffer->write_index];
    
//  *  2 写入数据 （1 数据长度作为帧头， 2 数据内容作为帧体）
    int remain_len=write_sub_buffer->total_len-write_sub_buffer->data_len;
    if(write_data_len+1>remain_len)
    {
        pthread_mutex_unlock(&buffer->swap_lock);
        log_error("剩余缓冲区长度不足");
        return -1;
    }
    write_sub_buffer->data_ptr[write_sub_buffer->data_len]=write_data_len;//写入数据长度作为帧头
    memcpy(write_sub_buffer->data_ptr+write_sub_buffer->data_len+1,write_data ,write_data_len); //写入帧体

//  *  3 增加缓冲区数据长度
    write_sub_buffer->data_len+=write_data_len+1;

    pthread_mutex_unlock(&buffer->swap_lock);
     return 0;

}

/**
 * @brief 从缓冲区读取数据
 * @param app_buffer_t* 缓冲区指针
 * @param  char* 读取数据容器
 * @param int 读取数据容器长度
 * @return int 读取成功返回 实际的数据长度，失败返回-1
 * 步骤：
 * 1 获取负责读的子缓冲区 
 * 2 判断是否有数据 
 *      2.1 没有数据  要进行缓冲区的切换
 *      2.2 再次 获取负责读的子缓冲区 
 *      2.3 检查是否有数据 如果确实没有 返回0 
 *  3 有数据  读取数据
 *      3.1  取最顶上的帧头 
 *      3.2  比较要读取的数据长度和  读取数据容器的长
 *      3.3  读取数据 （1 把数据内容读取到数据容器中 2 后面的数据覆盖前面的 3 调整缓冲区数据长度）
 *  4 返回实际读取的长度
 *      
 *   
 */
int app_buffer_read(app_buffer_t *buffer, char *read_buff, int read_buff_len)
{
    //A 此处加锁 
    pthread_mutex_lock(&buffer->read_lock);
    // * 1 获取负责读的子缓冲区 
    sub_app_buffer_t *read_sub_buffer = buffer->sub_buffer[buffer->read_index];
    // * 2 判断是否有数据 
    //B 1
    if(read_sub_buffer->data_len == 0)
    {
    // *      2.1 没有数据  要进行缓冲区的切换
          app_buffer_swap(buffer);
    // *      2.2 再次 获取负责读的子缓冲区 
          read_sub_buffer = buffer->sub_buffer[buffer->read_index];
    // *      2.3 检查是否有数据 如果确实没有 返回0 
          if(read_sub_buffer->data_len == 0)
          {
             pthread_mutex_unlock(&buffer->read_lock);
              return 0;
          }
    }
  //C
    // *  3 有数据  读取数据
    // *      3.1  取最顶上的帧头 
          int read_len =  read_sub_buffer->data_ptr[0];
    // *      3.2  比较要读取的数据长度和  读取数据容器的长
          if(read_len > read_buff_len)
          {
            pthread_mutex_unlock(&buffer->read_lock);
              log_error("读取容器空间不足");
              return -1;
          }
  //D
    // *      3.3  读取数据 （1 把数据内容读取到数据容器中 2 后面的数据覆盖前面的 3 调整缓冲区数据长度）
          memcpy(read_buff,read_sub_buffer->data_ptr+1,read_len);
          int rm_size=read_len+1;
          memmove(read_sub_buffer->data_ptr,read_sub_buffer->data_ptr+rm_size,read_sub_buffer->data_len -rm_size);
          read_sub_buffer->data_len -= rm_size;
    //E
    pthread_mutex_unlock(&buffer->read_lock);
    // *  4 返回实际读取的长度
          return read_len;
}



/**
 * @brief 缓冲区的销毁
 * @param app_buffer_t* 缓冲区指针
 */
void app_buffer_destroy(app_buffer_t *buffer)
{
    if(buffer)
    {
        for (size_t i = 0; i < 2; i++)
        {
            if(buffer->sub_buffer[i])
            {
                free(buffer->sub_buffer[i]->data_ptr);
                free(buffer->sub_buffer[i]);
            }
        }
        pthread_mutex_destroy(&buffer->read_lock);
        pthread_mutex_destroy(&buffer->swap_lock);
        free(buffer);
    }


}